﻿#region Imports
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml;
using CommonUtilities.Util;
using Microsoft.VisualBasic;
#endregion

namespace ExpenseMgrUtil
{
    public partial class frmExpMgrUtil : Form
    {
        bool cb4 = false;
        public bool RestrictGenerate { get; set; }

        #region Declarations
        private const string sCopyClipbrd = "&Copy to clipboard!";
        private const string sAlreayCopied = "Already &copied!";
        private const string sOverwriteClipbrd = "Do you want to overwrite clipboard contents?";
        private const string sConfirmation = "Confirmation..";
        private const string sheetTracker = "Tracker!";
        private const string sDelim = ",";
        private const char cDot = '.';

        private string sColsRough = ConfigurationManager.AppSettings["Cols_Rough"];
        private string sColsTracker = ConfigurationManager.AppSettings["Cols_Tracker"];

        private const string sNoError = "No errors";
        private const string cNewLine = "\r\n";

        private const int waitSecs = 5;
        private int iTickCounter = 0;
        #endregion

        #region Constructors
        public frmExpMgrUtil()
        {
            InitializeComponent();
            txtColumns.ReadOnly = true;

            InitializeControls();
        }
        #endregion

        #region Events
        #region Controls
        private void btnGenerate_Click(object sender, EventArgs e)
        {
            if (txtRows.Text.Contains('~'))
            {
                pnlRange.Visible = true;
                ParseRange();
                return;
            }

            if (RestrictGenerate) return;
            if (Utilities.GetControlName(sender) == btnGenerate.Name) StopTimer();

            // Control lastFocus = this.Controls.Cast<Control>().Where(ctrl => ctrl.Focused).FirstOrDefault();
            btnGenerate.Focus();

            txtColumns.Text = chkTracker.Checked ? sColsTracker : sColsRough;

            string sRows = txtRows.Text; string sCols = txtColumns.Text;
            btnCopyClipbrd.Text = sCopyClipbrd;

            txtOutput.Text = GenerateOutput(ref sRows, sCols);
            txtRows.Text = sRows;

            if (chkAutoCopy.Checked) btnCopyClipbrd_Click(sender, e);
            // if (!IsNull(lastFocus)) lastFocus.Focus();
            txtRows.Focus();
            txtRows.SelectAll();
        }

        private void btnCopyClipbrd_Click(object sender, EventArgs e)
        {
            try
            {
                string sOutput = txtOutput.Text;
                if (txtColumns.Focused) sOutput = txtColumns.Text;
                else if (txtRows.Focused) sOutput = txtRows.Text;
                else if (txtLowerBound.Focused) sOutput = txtLowerBound.Text;
                else if (txtUpperBound.Focused) sOutput = txtUpperBound.Text;
                //else if (.Focused) sText = .Text;
                else sOutput = txtOutput.Text;

                if (!String.IsNullOrEmpty(sOutput) &&
                String.IsNullOrEmpty(Clipboard.ContainsText(TextDataFormat.Text) ? Clipboard.GetText() : String.Empty))
                    Clipboard.SetText(sOutput);
                else
                {
                    if ((Clipboard.ContainsText(TextDataFormat.Text) ? Clipboard.GetText() : String.Empty) == sOutput)
                        btnCopyClipbrd.Text = sAlreayCopied;
                    else
                    {
                        if (!String.IsNullOrEmpty(sOutput))
                        {
                            if (MessageBox.Show(sOverwriteClipbrd, sConfirmation, MessageBoxButtons.YesNo) == DialogResult.Yes)
                            {
                                Clipboard.SetText(sOutput); this.WindowState = FormWindowState.Minimized;
                                RestrictGenerate = true; numHeadCount.Value = numHeadCount.Minimum; RestrictGenerate = false;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            { MessageBox.Show("An error occurred..\r\n" + ex.Message + "\r\n\r\n" + ex.StackTrace, "Error.."); }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            InitializeControls();
        }

        private void btnFromClipbrd_Click(object sender, EventArgs e)
        {
            btnCopyClipbrd.Text = sCopyClipbrd;
            if (Clipboard.ContainsText(TextDataFormat.Text)) txtRows.Text = Clipboard.GetText().Replace(cNewLine, sDelim);
        }

        private void chkAutoCopy_CheckedChanged(object sender, EventArgs e)
        {
            btnCopyClipbrd.Enabled = !chkAutoCopy.Checked;
        }

        private void txtRows_TextChanged(object sender, EventArgs e)
        {
            btnGenerate.Enabled = !String.IsNullOrEmpty(txtRows.Text.Trim());
            btnCopyClipbrd.Text = sCopyClipbrd;

            if (txtRows.Text.Contains('~'))
            {
                pnlRange.Visible = true;
                ParseRange();
            }
        }

        private void txtColumns_TextChanged(object sender, EventArgs e)
        {
            btnCopyClipbrd.Text = sCopyClipbrd;
        }

        private void btnBase_Click(object sender, EventArgs e)
        {
            Process.Start("explorer.exe", Application.StartupPath);
            btnCopyClipbrd.Text = sCopyClipbrd;
        }

        private void mnuToggleTracker_Click(object sender, EventArgs e)
        {
            chkTracker.Checked = !chkTracker.Checked;
        }
        #endregion

        #region Menus
        private void mnuExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void mnuEmptyClipboard_Click(object sender, EventArgs e)
        {
            Clipboard.Clear();
        }
        #endregion
        #endregion

        #region Methods
        private void InitializeControls()
        {
            RestrictGenerate = true;

            #region Events
            // Clicks
            mnuGenerate.Click += btnGenerate_Click;
            mnuCopyToClipboard.Click += btnCopyClipbrd_Click;
            mnuClear.Click += btnClear_Click;
            mnuCopyFromClipboard.Click += btnFromClipbrd_Click;
            mnuBase.Click += btnBase_Click;
            mnuBackupFile.Click += btnBackup_Click;

            // Head-count
            mnuIncrease.Click += (object sender, EventArgs e) => { if (numHeadCount.Value + numHeadCount.Increment <= numHeadCount.Maximum) numHeadCount.Value = numHeadCount.Value + numHeadCount.Increment; StartTimer(); };
            mnuDecrease.Click += (object sender, EventArgs e) => { if (numHeadCount.Value - numHeadCount.Increment >= numHeadCount.Minimum) numHeadCount.Value = numHeadCount.Value - numHeadCount.Increment; StartTimer(); };

            // Generate
            chkTracker.CheckedChanged += btnGenerate_Click;
            numHeadCount.Leave += btnGenerate_Click;
            #endregion

            #region Controls
            // Default buttons
            this.AcceptButton = btnGenerate;

            // Design
            pnlRange.Location = txtColumns.Location;

            // Initializing fields
            chkAutoCopy.Checked = true;
            btnCopyClipbrd.Enabled = !chkAutoCopy.Checked;
            btnCopyClipbrd.Text = sCopyClipbrd;
            chkTracker.Checked = false;
            txtColumns.Text = sColsRough;
            numHeadCount.ReadOnly = true;
            pnlRange.Visible = false;
            tmrClipboardChecker.Start();

            if (IsNumeric(ConfigurationManager.AppSettings["MaxPersons"]))
                numHeadCount.Maximum = Convert.ToInt32(ConfigurationManager.AppSettings["MaxPersons"]);
            numYear.Minimum = DateTime.Now.Year - 1;
            numYear.Maximum = DateTime.Now.Year + 1;
            numMonth.Value = DateTime.Now.Month;
            numYear.Value = DateTime.Now.Year;

            // Cleanup
            txtRows.Clear();
            txtOutput.Clear();

            // Tooltips
            mnuCopyFromClipboard.Text = ttipMain.GetToolTip(btnCopyClipbrd);
            mnuGenerate.ToolTipText = ttipMain.GetToolTip(btnGenerate);
            mnuCopyToClipboard.ToolTipText = ttipMain.GetToolTip(btnCopyClipbrd);
            mnuClear.ToolTipText = ttipMain.GetToolTip(btnClear);
            mnuExit.ToolTipText = "Click to exit!";
            mnuBase.ToolTipText = ttipMain.GetToolTip(btnBase);
            mnuBackupFile.ToolTipText = ttipMain.GetToolTip(btnBackup);

            // Focusing
            txtRows.Focus();
            #endregion

            cb4 = btnCopyClipbrd.Enabled;
            RestrictGenerate = false;
        }

        private void StartTimer()
        {
            if (!tmrHeadCountWaiter.Enabled) tmrHeadCountWaiter.Enabled = true;
            tmrHeadCountWaiter.Start();
            iTickCounter = 0; // waitSecs * 1000 / tmrHeadCountWaiter.Interval;
        }

        private void StopTimer()
        {
            tmrHeadCountWaiter.Stop();
        }

        private string GenerateOutput(ref string sRows, string sCols)
        {
            sRows = sRows.Trim().Replace(" ", "");
            sCols = sCols.Trim().Replace(" ", "");

            List<string> lstRows = sRows.Split(sDelim.ToCharArray()).ToList();
            List<string> lstColumns = sCols.Split(sDelim.ToCharArray()).ToList();
            sRows = "";

            string sOutput = "";
            foreach (string row in lstRows)
            {
                if (!String.IsNullOrEmpty(row) && IsNumeric(row))
                {
                    string item = "";
                    foreach (string col in lstColumns)
                    {
                        if (!String.IsNullOrEmpty(col))
                            item += "=" + (chkTracker.Checked ? (col == lstColumns.Last() ? "-" : "") + sheetTracker : "") + "$" + col + "$" + GetInteger(row)
                                        + (col == lstColumns.Last() && numHeadCount.Value > 1 ? "/" + numHeadCount.Value : "") + "\t";
                    }

                    sRows += row + sDelim;
                    sOutput += item.TrimEnd('\t') + "~";
                }
            }

            sRows = sRows.TrimEnd(sDelim.ToCharArray());
            return sOutput.TrimEnd('~').Replace("~", cNewLine);
        }

        private bool IsNumeric(object value)
        {
            return Information.IsNumeric(value);
        }

        private bool IsNull(object value)
        {
            return Information.IsNothing(value);
        }

        private string GetInteger(object value)
        {
            return value.ToString().Contains(cDot) ? Left(value, value.ToString().IndexOf(cDot)) : (string)value;
        }

        private string Left(object value, int length)
        {
            return Strings.Left((string)value, length);
        }
        #endregion

        private void btnBackup_Click(object sender, EventArgs e)
        {
            string prefix = ConfigurationManager.AppSettings["FileNamePrefix"];
            string separator = "_";
            string sExtn = ConfigurationManager.AppSettings["FileNameExtn"];
            string backupPath = ConfigurationManager.AppSettings["FileBackupPath"];

            string filename = prefix + separator + numYear.Value + separator + (numMonth.Value < 10 ? "0" : "") + numMonth.Value + sExtn;
            string filepath = ConfigurationManager.AppSettings["FilePath"].TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar + filename;

            if (File.Exists(filepath))
                File.Copy(filepath, backupPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(filename) + " [" + DateTime.Now.ToString(ConfigurationManager.AppSettings["BackupTimestampFormat"]) + "] " + sExtn);
        }

        private void RangeLimit_TextChanged(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(txtLowerBound.Text) && !String.IsNullOrEmpty(txtUpperBound.Text)
            && IsNumeric(txtLowerBound.Text) && IsNumeric(txtUpperBound.Text))
                btnOK.Enabled = Convert.ToInt32(txtUpperBound.Text.Split('.')[0]) > Convert.ToInt32(txtLowerBound.Text.Split('.')[0]);
            else
                btnOK.Enabled = false;

            EvaluateErrors();
        }

        private void txtRows_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Escape) txtRows.Clear();
            //else if (e.KeyChar == '~')
            //{
            //    pnlRange.Visible = true;
            //    txtLowerBound.Text = txtUpperBound.Text = "";
            //
            //    e.Handled = true;
            //}
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            string sRange = "";
            for (int i = Convert.ToInt32(txtLowerBound.Text); i <= Convert.ToInt32(txtUpperBound.Text); i++)
                sRange += i + ",";

            txtRows.Text = sRange.TrimEnd(',');
            pnlRange.Visible = false;
            txtRows.Focus();
            SendKeys.Send("{End}");
        }

        private void pnlRange_VisibleChanged(object sender, EventArgs e)
        {
            List<string> ignore = new List<string>();
            ignore.Add(btnCopyClipbrd.Name);
            ignore.AddRange((pnlRange.Name + ';' + lblColumns.Name).Split(';'));
            this.Controls.Cast<Control>().Where(ctrl => !ignore.Contains(ctrl.Name)).ToList().ConvertAll(ctrl => ctrl.Enabled = !pnlRange.Visible);
            if (!pnlRange.Visible) btnCopyClipbrd.Enabled = cb4;
            else { cb4 = btnCopyClipbrd.Enabled; btnCopyClipbrd.Enabled = false; }

            this.AcceptButton = pnlRange.Visible ? btnOK : btnGenerate;
            lblColumns.Text = (pnlRange.Visible ? "Errors" : "Columns") + ":";
        }

        private void RangeLimit_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Escape) pnlRange.Visible = false;
            else if (e.KeyChar == '~' || e.KeyChar == '.')
            {
                if (txtLowerBound.Focused) txtUpperBound.Focus();
                else if (txtUpperBound.Focused) txtLowerBound.Focus();

                e.Handled = true;
            }
        }

        private void EvaluateErrors()
        {
            if (btnOK.Enabled)
                lblError.Text = sNoError;
            else
            {
                string sErrors = ""; string sErrors2 = "";

                if (String.IsNullOrEmpty(txtLowerBound.Text)) sErrors += "Blanks: L;";
                if (String.IsNullOrEmpty(txtUpperBound.Text)) sErrors += "Blanks: U;";
                if (!IsNumeric(txtLowerBound.Text)) sErrors += "Num: L;";
                if (!IsNumeric(txtUpperBound.Text)) sErrors += "Num: U;";
                if (IsNumeric(txtLowerBound.Text) && IsNumeric(txtUpperBound.Text))
                    if (Convert.ToInt32(txtUpperBound.Text) < Convert.ToInt32(txtLowerBound.Text))
                        sErrors += "L>U;";

                sErrors = sErrors.TrimEnd(';');
                foreach (string prefx in sErrors.Split(';').Select(err => err.Split(':').First()).Distinct())
                {
                    //if (sErrors.Split(';').Select(err => err.Split(':').First()).Where(err => err == prefx).Count() > 1)
                    if (sErrors.Split(';').Where(err => err.StartsWith(prefx)).Count() > 1)
                    {
                        string sPrefix = prefx + ": "; string sCurr = sPrefix;
                        foreach (string items in sErrors.Split(';').Where(err => err.StartsWith(prefx)))
                            sCurr += items.Replace(sPrefix, "") + "/";

                        sErrors2 += sCurr.TrimEnd('/');
                    }
                    else
                        sErrors2 += sErrors.Split(';').Where(err => err.StartsWith(prefx)).First();

                    sErrors2 += "      ";
                }

                lblError.Text = sErrors2;
            }
        }

        private void lblError_TextChanged(object sender, EventArgs e)
        {
            lblError.ForeColor = (lblError.Text == sNoError) ? Color.Green : Color.Red;
        }

        private void ParseRange()
        {
            string sText = txtRows.Text;
            if (sText.Contains('~'))
            {
                string[] parts = sText.Split('~');
                txtLowerBound.Text = parts.First().Trim();
                txtUpperBound.Text = (parts.Count() > 1 ? parts[1] : "").Trim();

                if (!sText.StartsWith("~") && !sText.EndsWith("~"))
                    btnOK.Focus();
                else if (sText.StartsWith("~"))
                    txtLowerBound.Focus();
                else if (sText.EndsWith("~"))
                    txtUpperBound.Focus();
            }
        }

        private void btnSettings_Click(object sender, EventArgs e)
        {
            string sConfigPath = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath).FilePath;
            //XmlReader xmlConfig = XmlReader.Create(sConfigPath);
            //MessageBox.Show(xmlConfig.ReadContentAsString());

            // Read from XML :: http://support.microsoft.com/kb/307548
            XmlTextReader reader = new XmlTextReader(sConfigPath);
            string sXML = ""; // RKD
            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element: // The node is an element.
                        sXML += "<" + reader.Name + ">";
                        //Console.Write("<" + reader.Name);
                        //Console.WriteLine(">");
                        break;
                    case XmlNodeType.Text: //Display the text in each element.
                        sXML += reader.Value;
                        //Console.WriteLine (reader.Value);
                        break;
                    case XmlNodeType.EndElement: //Display the end of the element.
                        sXML += "</" + reader.Name + ">";
                        //Console.Write("</" + reader.Name);
                        //Console.WriteLine(">");
                        break;
                }
            }
            MessageBox.Show(sXML);
            //Console.ReadLine();

            //Dictionary<string, string> dictAppSettings = ConfigurationManager.AppSettings.Cast<string>().ToDictionary<string, string>();
            Dictionary<string, string> dictAppSettings = new Dictionary<string, string>();
            DataTable dtAppSettings = new DataTable("AppSettings");
            DataColumn dcKey = new DataColumn("Key");
            DataColumn dcValue = new DataColumn("Value");
            dtAppSettings.Columns.Add(dcKey); dtAppSettings.Columns.Add(dcValue);
            foreach (string key in ConfigurationManager.AppSettings)
            {
                dictAppSettings.Add(key, ConfigurationManager.AppSettings[key]);

                DataRow drSettings = dtAppSettings.NewRow();
                drSettings[dcKey] = key;
                drSettings[dcValue] = dictAppSettings[key];
                dtAppSettings.Rows.Add(drSettings);
            }

            // Reset & count-down
            frmResetInfo frmResetInfo = new frmResetInfo(5);
            frmResetInfo.Height = this.Height - 200;
            frmResetInfo.Width = this.Width - 50;
            this.Controls.Cast<Control>().ToList().ConvertAll(ctrl => ctrl.Enabled = false);
            frmResetInfo.ShowDialog(this);
            frmResetInfo.Dispose();
        }

        private void tmrClipboardChecker_Tick(object sender, EventArgs e)
        {
            bool trgt = false;
            if ((Clipboard.ContainsText(TextDataFormat.Text) ? Clipboard.GetText() : String.Empty) == txtOutput.Text)
            { btnCopyClipbrd.Text = sAlreayCopied; trgt = !chkAutoCopy.Enabled; }
            else
            { btnCopyClipbrd.Text = sCopyClipbrd; trgt = true; }

            if (String.IsNullOrEmpty(txtOutput.Text)) trgt = false;
            if (!pnlRange.Visible) cb4 = trgt;

            if (btnCopyClipbrd.Enabled != trgt && !pnlRange.Visible) btnCopyClipbrd.Enabled = trgt;
        }

        private void tmrHeadCountWaiter_Tick(object sender, EventArgs e)
        {
            iTickCounter++;
            if (waitSecs * 1000 - tmrHeadCountWaiter.Interval * iTickCounter <= 0)
            { tmrHeadCountWaiter.Stop(); btnGenerate_Click(sender, e); }
        }

        private void mnuBase_Click(object sender, EventArgs e)
        {

        }

        private void mnuBackupFile_Click(object sender, EventArgs e)
        {

        }

        private void btnCopyClipbrd_EnabledChanged(object sender, EventArgs e)
        {

        }

        private void picCalc_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
            Process.Start("calc.exe");
        }
    }

    public static class Extensions
    {
        private static void Reset(this Timer tmr)
        {

        }
    }
}


/*

this.btnClear.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnClear.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.btnClear.ForeColor = System.Drawing.Color.Red;
this.btnClear.TabIndex = 4;
this.btnClear.Text = "X";
this.ttipMain.SetToolTip(this.btnClear, "Clear inputs");

*/